﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;

namespace YJKSparseDistance.ModelLayer
{
	public class BaseWayMapBean
	{
		public BaseWayMapBean(List<BulidingCurvePakcer> lstRoomBoundary, List<BulidingCurvePakcer> lstObstructurBoundary, List<WallLocationCurveBean> lstWallLocationCurveBean, List<XYZ> buildFreeEnds)
		{
			this.m_lstWallLocationCurveBean.AddRange(lstWallLocationCurveBean);
			this.m_lstAllFreeEnd.AddRange(buildFreeEnds);
			for (int i = 0; i < this.m_nAsyncCount; i++)
			{
				this.m_lstUseAsyncDelegate.Add(new BaseWayMapBean.DelegateCalculate(BaseWayMapBean.ThreadMethodGetLinkWay));
			}
			this.SetRoomBuildCurvePacker(lstRoomBoundary);
			this.SetObstructureCurvePacker(lstObstructurBoundary);
			this.SetBuildingLink();
		}

		public List<BaseCurvePacker> GetBuildingRunWay()
		{
			List<BaseCurvePacker> list = new List<BaseCurvePacker>();
			list.AddRange(this.m_lstNowAppendEndCurves_BetweenBuilding.Cast<BaseCurvePacker>());
			return list;
		}

		public List<BaseCurvePacker> SetStartPoint(EndPointPacker input)
		{
			List<BaseCurvePacker> list = new List<BaseCurvePacker>();
			this.SetEndPoint(input, 0);
			list.AddRange(this.m_lstlstAppendEndCurves[0].Cast<BaseCurvePacker>());
			return list;
		}

		public List<BaseCurvePacker> SetEndPoint(EndPointPacker input)
		{
			List<BaseCurvePacker> list = new List<BaseCurvePacker>();
			this.SetEndPoint(input, 1);
			list.AddRange(this.m_lstlstAppendEndCurves[1].Cast<BaseCurvePacker>());
			return list;
		}

		private void SetEndPoint(EndPointPacker inputPointPacker, int useEndPointIndex)
		{
			if (useEndPointIndex != 0 && 1 != useEndPointIndex)
			{
                throw new System.ArgumentException();
			}
			XYZ useEndPoint = inputPointPacker.UseEndPoint;
			XYZ obj = useEndPoint;
			if (inputPointPacker.AppendPoint != null)
			{
				obj = inputPointPacker.AppendPoint;
			}
			if (this.m_lstEndPoints[useEndPointIndex] != null && useEndPoint.IsAlmostEqualTo(this.m_lstEndPoints[useEndPointIndex]))
			{
				return;
			}
			this.m_lstEndPoints[useEndPointIndex] = useEndPoint;
			this.m_lstlstAppendEndCurves[useEndPointIndex] = new List<EndCurvPacker>();
			int hashCode = this.m_useCompare.GetHashCode(obj);
			if (this.m_WayCache.ContainsKey(hashCode))
			{
				this.m_lstlstAppendEndCurves[useEndPointIndex].AddRange(this.m_WayCache[hashCode]);
				return;
			}
			List<BulidingCurvePakcer> lstAllTempBuildCurvePackers = this.MakeTempBuildBoundary();
			List<Curve> list = this.GetDoorFreeLink(useEndPoint);
			if (this.m_lstEndPoints[0] != null && !this.m_lstEndPoints[0].IsAlmostEqualTo(useEndPoint))
			{
				list.Add(Line.CreateBound(this.m_lstEndPoints[0], useEndPoint));
			}
			list = this.QuickCurveCheck(list);
			this.m_lstlstAppendEndCurves[useEndPointIndex] = this.GetLinkWay(lstAllTempBuildCurvePackers, list, this.m_lstEndPoints[useEndPointIndex]);
			List<EndCurvPacker> list2 = new List<EndCurvPacker>();
			list2.AddRange(this.m_lstlstAppendEndCurves[useEndPointIndex]);
			this.m_WayCache.Add(hashCode, list2);
		}

		private void SetRoomBuildCurvePacker(List<BulidingCurvePakcer> inputValue)
		{
			this.m_lstAllDoorFreeCurve = (from n in inputValue
			where n.IfDoorFreeEnd
			select n).ToList<BulidingCurvePakcer>();
			this.m_lstThisBulidCurvePacker_ByRoom = inputValue;
		}

		private void SetObstructureCurvePacker(List<BulidingCurvePakcer> inputValue)
		{
			this.m_lstThisBulidCurvePacker_ByObstructure = inputValue;
		}

		private void SetBuildingLink()
		{
			List<BulidingCurvePakcer> list = this.MakeTempBuildBoundary();
			List<Curve> list2 = Utility.GetAllFreeEndLink(this.m_lstAllFreeEnd, this.m_dTolerance);
			list2 = this.QuickCurveCheck(list2);
			List<Curve> collection = (from n in list
			where n.IfCanGo
			select n.ThisCurve).ToList<Curve>();
			list2.AddRange(collection);
			List<EndCurvPacker> linkWay = this.GetLinkWay(list, list2, null);
			this.m_lstNowAppendEndCurves_BetweenBuilding = linkWay;
		}

		private BulidingCurvePakcer FindNearestDoorFreeEndCurve(XYZ input)
		{
			IOrderedEnumerable<BulidingCurvePakcer> source = from k in this.m_lstAllDoorFreeCurve
			orderby k.MidPoint.DistanceTo(input)
			select k;
			if (source.Count<BulidingCurvePakcer>() > 0)
			{
				return source.ElementAt(0);
			}
			return null;
		}

		private List<Curve> QuickCurveCheck(List<Curve> input)
		{
			List<Curve> list = new List<Curve>();
			bool flag = true;
			foreach (Curve curve in input)
			{
				flag = true;
				foreach (WallLocationCurveBean wallLocationCurveBean in this.m_lstWallLocationCurveBean)
				{
                    if ((int)curve.Intersect(wallLocationCurveBean.UseCurve) != 4)
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					list.Add(curve);
				}
			}
			return list;
		}

		private List<Curve> GetDoorFreeLink(XYZ inputEndPoint)
		{
			BulidingCurvePakcer bulidingCurvePakcer = this.FindNearestDoorFreeEndCurve(inputEndPoint);
			List<Curve> list = new List<Curve>();
			List<XYZ> list2 = new List<XYZ>();
			list2.Add(inputEndPoint);
			if (bulidingCurvePakcer != null)
			{
				for (int i = 0; i < 2; i++)
				{
					list2.Add(bulidingCurvePakcer.ThisCurve.GetEndPoint(i));
					try
					{
						Line item = Line.CreateBound(inputEndPoint, bulidingCurvePakcer.ThisCurve.GetEndPoint(i));
						list.Add(item);
					}
					catch (ArgumentsInconsistentException)
					{
					}
				}
			}
			foreach (XYZ xyz in list2)
			{
				foreach (XYZ xyz2 in this.m_lstAllFreeEnd)
				{
					try
					{
						Line item = Line.CreateBound(xyz, xyz2);
						list.Add(item);
					}
					catch (ArgumentsInconsistentException)
					{
					}
				}
			}
			return list;
		}

		private List<BulidingCurvePakcer> MakeTempBuildBoundary()
		{
			List<BulidingCurvePakcer> list = new List<BulidingCurvePakcer>();
			if (this.m_lstThisBulidCurvePacker_ByRoom != null)
			{
				list.AddRange(this.m_lstThisBulidCurvePacker_ByRoom);
			}
			if (this.m_lstThisBulidCurvePacker_ByObstructure != null)
			{
				list.AddRange(this.m_lstThisBulidCurvePacker_ByObstructure);
			}
			return list;
		}

		private List<EndCurvPacker> GetLinkWay(List<BulidingCurvePakcer> lstAllTempBuildCurvePackers, List<Curve> lstTempCurve, XYZ endPoint = null)
		{
			lstAllTempBuildCurvePackers = (from n in lstAllTempBuildCurvePackers
			where !n.IfCanIntersection
			select n).ToList<BulidingCurvePakcer>();
			if (lstTempCurve.Count > 10)
			{
				List<EndCurvPacker> list = new List<EndCurvPacker>();
				List<Curve[]> list2 = new List<Curve[]>();
				List<List<EndCurvPacker>> list3 = new List<List<EndCurvPacker>>();
				List<BaseWayMapBean.UseBean> list4 = new List<BaseWayMapBean.UseBean>();
				List<IAsyncResult> list5 = new List<IAsyncResult>();
				int num = 0;
				int num2 = lstTempCurve.Count / this.m_nAsyncCount;
				for (int i = 0; i < this.m_nAsyncCount; i++)
				{
					if (i != this.m_nAsyncCount - 1)
					{
						list2.Add(new Curve[num2]);
						lstTempCurve.CopyTo(num, list2[i], 0, num2);
						num += num2;
					}
					else
					{
						num2 = lstTempCurve.Count - num;
						list2.Add(new Curve[num2]);
						lstTempCurve.CopyTo(num, list2[i], 0, num2);
					}
					list3.Add(new List<EndCurvPacker>());
					list4.Add(new BaseWayMapBean.UseBean());
					list4[i].EndPoint = endPoint;
					list4[i].LstAllTempBuildCurvePackers = lstAllTempBuildCurvePackers;
					list4[i].LstTempCurve = list2[i].ToList<Curve>();
				}
				for (int j = 1; j < this.m_nAsyncCount; j++)
				{
					list5.Add(this.m_lstUseAsyncDelegate[j].BeginInvoke(list4[j], null, null));
				}
				BaseWayMapBean.ThreadMethodGetLinkWay(list4[0]);
				while (!BaseWayMapBean.IfAsyncEnd(list5))
				{
				}
				foreach (BaseWayMapBean.UseBean useBean in list4)
				{
					list.AddRange(useBean.ReturnValue);
				}
				return list;
			}
			return BaseWayMapBean.GetLinkWayCalculate(lstAllTempBuildCurvePackers, lstTempCurve, endPoint);
		}

		private static bool IfAsyncEnd(List<IAsyncResult> lstAsyncResult)
		{
			bool flag = true;
			foreach (IAsyncResult asyncResult in lstAsyncResult)
			{
				flag = (flag && asyncResult.IsCompleted);
			}
			return flag;
		}

		private static List<EndCurvPacker> GetLinkWayCalculate(List<BulidingCurvePakcer> lstAllTempBuildCurvePackers, List<Curve> lstTempCurve, XYZ endPoint)
		{
			bool flag = true;
			List<EndCurvPacker> list = new List<EndCurvPacker>();
			for (int i = 0; i < lstTempCurve.Count; i++)
			{
				flag = true;
				if (!(null == lstTempCurve[i]))
				{
					for (int j = 0; j < lstAllTempBuildCurvePackers.Count; j++)
					{
						if (!(null == lstAllTempBuildCurvePackers[j].ThisCurve))
						{
							IntersectionResultArray intersectionResultArray;
							SetComparisonResult setComparisonResult;
							try
							{
								setComparisonResult = lstTempCurve[i].Intersect(lstAllTempBuildCurvePackers[j].ThisCurve, out intersectionResultArray);
							}
							catch (Autodesk.Revit.Exceptions.InvalidOperationException)
							{
								goto IL_1AF;
							}
                            if ((int)setComparisonResult <= 16)
							{
                                switch ((int)setComparisonResult)
								{
								case 1:
								case 2:
								case 3:
								case 4:
									break;
								case 5:
								case 6:
								case 7:
									goto IL_1AA;
								case 8:
									if (endPoint == null || !endPoint.IsAlmostEqualTo(intersectionResultArray.get_Item(0).XYZPoint, 0.01))
									{
										if (!lstAllTempBuildCurvePackers[j].IfCanGo)
										{
											flag = false;
										}
										else if (intersectionResultArray.Size > 1 && (lstTempCurve[i] is Arc || lstAllTempBuildCurvePackers[j].ThisCurve is Arc))
										{
											flag = false;
										}
										else if ((intersectionResultArray.Size != 1 || !(lstTempCurve[i] is Arc) || !(lstAllTempBuildCurvePackers[j].ThisCurve is Arc)) && !Utility.IfIntersectionAtEnd(lstAllTempBuildCurvePackers[j].ThisCurve, intersectionResultArray.get_Item(0)))
										{
											flag = false;
										}
									}
									break;
								default:
									if (setComparisonResult != SetComparisonResult.Subset)
									{
										goto IL_1AA;
									}
									if (!lstAllTempBuildCurvePackers[j].IfCanGo)
									{
										flag = false;
									}
									break;
								}
							}
							else if (setComparisonResult != SetComparisonResult.Superset)
							{
								if (setComparisonResult != SetComparisonResult.Equal)
								{
									goto IL_1AA;
								}
								if (!lstAllTempBuildCurvePackers[j].IfCanGo)
								{
									flag = false;
								}
							}
							else if (!lstAllTempBuildCurvePackers[j].IfCanGo)
							{
								flag = false;
							}
							IL_1AC:
							if (flag)
							{
								goto IL_1AF;
							}
							break;
							IL_1AA:
							flag = false;
							goto IL_1AC;
						}
						IL_1AF:;
					}
					if (flag)
					{
						list.Add(new EndCurvPacker(lstTempCurve[i]));
					}
				}
			}
			return list;
		}

		private static void ThreadMethodGetLinkWay(object input)
		{
			if (input is BaseWayMapBean.UseBean)
			{
				(input as BaseWayMapBean.UseBean).ReturnValue.AddRange(BaseWayMapBean.GetLinkWayCalculate((input as BaseWayMapBean.UseBean).LstAllTempBuildCurvePackers, (input as BaseWayMapBean.UseBean).LstTempCurve, (input as BaseWayMapBean.UseBean).EndPoint));
				(input as BaseWayMapBean.UseBean).IfFinal = true;
			}
		}

		private List<BulidingCurvePakcer> m_lstThisBulidCurvePacker_ByRoom;

		private List<BulidingCurvePakcer> m_lstThisBulidCurvePacker_ByObstructure;

		private List<WallLocationCurveBean> m_lstWallLocationCurveBean = new List<WallLocationCurveBean>();

		private List<EndCurvPacker> m_lstNowAppendEndCurves_BetweenBuilding;

		private List<XYZ> m_lstAllFreeEnd = new List<XYZ>();

		private List<BulidingCurvePakcer> m_lstAllDoorFreeCurve = new List<BulidingCurvePakcer>();

		private List<List<EndCurvPacker>> m_lstlstAppendEndCurves = new List<List<EndCurvPacker>>
		{
			new List<EndCurvPacker>(),
			new List<EndCurvPacker>()
		};

		private List<XYZ> m_lstEndPoints = new List<XYZ>
		{
			null,
			null
		};

		private Dictionary<XYZ, List<EndCurvPacker>> m_dicEndPointCurves = new Dictionary<XYZ, List<EndCurvPacker>>();

		private XYZCompare m_useCompare = XYZCompare.GetCompare();

		private Dictionary<int, List<EndCurvPacker>> m_WayCache = new Dictionary<int, List<EndCurvPacker>>();

		private double m_dTolerance = 0.0033;

		private List<BaseWayMapBean.DelegateCalculate> m_lstUseAsyncDelegate = new List<BaseWayMapBean.DelegateCalculate>();

		private int m_nAsyncCount = 4;

		private delegate void DelegateCalculate(object input);

		private class UseBean
		{
			public List<BulidingCurvePakcer> LstAllTempBuildCurvePackers
			{
				get
				{
					return this.m_lstAllTempBuildCurvePackers;
				}
				set
				{
					this.m_lstAllTempBuildCurvePackers = value;
				}
			}

			public List<Curve> LstTempCurve
			{
				get
				{
					return this.m_lstTempCurve;
				}
				set
				{
					this.m_lstTempCurve = value;
				}
			}

			public XYZ EndPoint
			{
				get
				{
					return this.m_endPoint;
				}
				set
				{
					this.m_endPoint = value;
				}
			}

			public List<EndCurvPacker> ReturnValue
			{
				get
				{
					return this.m_ReturnValue;
				}
			}

			public bool IfFinal
			{
				get
				{
					return this.ifFinal;
				}
				set
				{
					this.ifFinal = value;
				}
			}

			private List<BulidingCurvePakcer> m_lstAllTempBuildCurvePackers;

			private List<Curve> m_lstTempCurve;

			private XYZ m_endPoint;

			private List<EndCurvPacker> m_ReturnValue = new List<EndCurvPacker>();

			private bool ifFinal;
		}
	}
}
